# -*-coding:utf-8-*-
import numpy as np
import pandas as pd
import requests
import json
import time
from datetime import datetime
from loguru import logger
from private_connection import private_restapi_binance

主题 = 'BTCBUSD策略'



def get_kline_U(SYMBOL, INTERVAL, LIMIT, TIMEOUT):
    url = 'https://fapi.binance.com/fapi/v1/klines'
    params = {
        'symbol': SYMBOL,
        'interval': INTERVAL,
        'limit': LIMIT,
        'endTime': int(time.mktime(datetime.now().timetuple()) * 1000)
    }
    try:
        response = requests.get(url, params=params, timeout=TIMEOUT)
        if response.status_code == 200:
            data = json.loads(response.text.encode())
            if len(data) > 0:
                # 0,1,2,3,4,5列分别为:时间,O,H,L,C,V
                data = np.array(data)[:, [0, 1, 2, 3, 4, 5]].astype(float)
            else:
                data = []
        else:
            data = []
    except requests.exceptions.RequestException as e:
        data = []

    df = pd.DataFrame(data, columns=['time', 'open', 'high', 'low', 'close', 'vol'])
    df.index = df['time'].apply(lambda x: datetime.fromtimestamp(int(x) / 1000))
    df = df.sort_index()
    df = df.drop(['time'], axis=1)
    return df


def 获取U本位账户余额(api_key, api_secret):
    PARAMS = {
        'api_key': f'{api_key}',
        'api_secret': f'{api_secret}',
        'method': 'GET',
        'host': 'https://fapi.binance.com',
        'path': '/fapi/v2/balance',
        'params': {
        }
    }

    res = private_restapi_binance(**PARAMS)
    data = json.loads(res.text.encode())
    df = pd.DataFrame(data)
    df.index = df['asset']
    df = df[['balance']].astype(float)
    return df


def 获取U本位持仓(api_key, api_secret):
    PARAMS = {
        'api_key': f'{api_key}',
        'api_secret': f'{api_secret}',
        'method': 'GET',
        'host': 'https://fapi.binance.com',
        'path': '/fapi/v2/account',
        'params': {
        }
    }

    res = private_restapi_binance(**PARAMS)
    data = json.loads(res.text.encode())
    df = pd.DataFrame(data['positions'])
    df.index = df['symbol']
    df = df[['positionAmt', 'maintMargin', 'unrealizedProfit']]
    df = df.astype(float)
    df = df[df.index.isin(['BTCUSDT','ETHUSDT','ETHBTC'])]
    # df = df[df['positionAmt'] != 0]
    return df

def 获取深度U本位(api_key, api_secret, SYMBOL, limit):
    PARAMS = {
        'api_key': f'{api_key}',
        'api_secret': f'{api_secret}',
        'method': 'GET',
        'host': 'https://fapi.binance.com',
        'path': '/fapi/v1/depth',
        'params': {
            'symbol': f'{SYMBOL}',
            'limit': f'{limit}',
        }
    }
    res = private_restapi_binance(**PARAMS)
    data = json.loads(res.text.encode())
    df_bid = pd.DataFrame(data['bids'],columns=['price','vol'])
    df_ask = pd.DataFrame(data['asks'],columns=['price','vol'])

    return df_bid,df_ask

def 准备挂单参数U本位(api_key, api_secret, SYMBOL, side, price, quantity, origClientOrderId):
    PARAMS = {
        'api_key': f'{api_key}',
        'api_secret': f'{api_secret}',
        'method': 'POST',
        'host': 'https://fapi.binance.com',
        'path': '/fapi/v1/order',
        'params': {
            'symbol': f'{SYMBOL}',
            'side': f'{side}',
            'type': 'LIMIT',
            'price': f'{price}',
            'quantity': f'{quantity}',
            'timeInForce': 'GTC',
            'newClientOrderId': f'{origClientOrderId}'
        }
    }
    return PARAMS


def 挂单(api_key, api_secret, SYMBOL, side, price, quantity, origClientOrderId):
    PARAMS = 准备挂单参数(api_key, api_secret, SYMBOL, side, price, quantity, origClientOrderId)
    res = private_restapi_binance(**PARAMS)
    res_info = json.loads(res.text.encode())
    if res.status_code == 200:
        info = '挂单成功'
    else:
        if res_info['code'] == -2010:
            info = '重复挂单'
        else:
            info = '\n(***非正常情况***)\n' + json.dumps(res_info)
    logger.info(info)
    if '非正常情况' in info:
        send(subject=主题, content=info)


def 挂单U本位(api_key, api_secret, SYMBOL, side, price, quantity, origClientOrderId):
    PARAMS = 准备挂单参数U本位(api_key, api_secret, SYMBOL, side, price, quantity, origClientOrderId)
    res = private_restapi_binance(**PARAMS)
    res_info = json.loads(res.text.encode())
    if res.status_code == 200:
        info = '挂单成功'
    else:
        if res_info['code'] == -4015:
            info = '重复挂单'
        else:
            info = '\n(***非正常情况***)\n' + json.dumps(res_info)
    logger.info(info)
    if '非正常情况' in info:
        send(subject=主题, content=info)


def 准备撤单参数(api_key, api_secret, SYMBOL, origClientOrderId):
    PARAMS = {
        'api_key': f'{api_key}',
        'api_secret': f'{api_secret}',
        'method': 'DELETE',
        'host': 'https://api.binance.com',
        'path': '/api/v3/order',
        'params': {
            'symbol': f'{SYMBOL}',
            'origClientOrderId': f'{origClientOrderId}'
        }
    }
    return PARAMS


def 准备撤单参数U本位(api_key, api_secret, SYMBOL, origClientOrderId):
    PARAMS = {
        'api_key': f'{api_key}',
        'api_secret': f'{api_secret}',
        'method': 'DELETE',
        'host': 'https://fapi.binance.com',
        'path': '/fapi/v1/order',
        'params': {
            'symbol': f'{SYMBOL}',
            'origClientOrderId': f'{origClientOrderId}'
        }
    }
    return PARAMS


def 撤单(api_key, api_secret, SYMBOL, origClientOrderId):
    PARAMS = 准备撤单参数(api_key, api_secret, SYMBOL, origClientOrderId)
    res = private_restapi_binance(**PARAMS)
    res_info = json.loads(res.text.encode())
    if res.status_code == 200:
        info = f'撤单成功,{origClientOrderId}'
    else:
        if res_info['code'] == -2011:
            info = f'当前无此挂单号:{origClientOrderId}'
        else:
            info = '\n(***非正常情况***)\n' + json.dumps(res_info)
    logger.info(info)
    if '非正常情况' in info:
        send(subject=主题, content=info)


def 撤单U本位(api_key, api_secret, SYMBOL, origClientOrderId):
    PARAMS = 准备撤单参数U本位(api_key, api_secret, SYMBOL, origClientOrderId)
    res = private_restapi_binance(**PARAMS)
    res_info = json.loads(res.text.encode())
    if res.status_code == 200:
        info = '撤单成功'
    else:
        if res_info['code'] == -2011:
            info = f'当前无此挂单号:{origClientOrderId}'
        else:
            info = '\n(***非正常情况***)\n' + json.dumps(res_info)
    logger.info(info)
    if '非正常情况' in info:
        send(subject=主题, content=info)


def get_x4(xx, rsi):
    """
    已知前面的收益率序列，计算：为了得到目标rsi，所需的新一个收益率是多少
    """
    x_pos = [x for x in xx if x > 0]
    x_neg = [abs(x) for x in xx if x < 0]
    sum_x_pos = sum(x_pos)
    sum_x_neg = sum(x_neg)

    if (sum_x_pos == 0) and (sum_x_neg == 0):
        sum_x_pos = 1
        sum_x_neg = 1

    rsi_ = sum_x_pos / (sum_x_neg + sum_x_pos)

    if rsi > rsi_:
        x = sum_x_neg * rsi / (1 - rsi) - sum_x_pos
    else:
        x = -(sum_x_pos * (1 / rsi - 1) - sum_x_neg)
    return x


def 获取挂单价格(SYMBOL, INTERVAL, LIMIT, TIMEOUT, 价格小数位数):
    df = get_kline_U(SYMBOL, INTERVAL, LIMIT, TIMEOUT)
    df['return'] = df['close'].pct_change()
    df['rsi_95'] = df['return'].rolling(3).apply(lambda x:get_x4(x,0.95))
    df['rsi_90'] = df['return'].rolling(3).apply(lambda x:get_x4(x,0.9))
    df['rsi_85'] = df['return'].rolling(3).apply(lambda x:get_x4(x,0.85))
    df['rsi_80'] = df['return'].rolling(3).apply(lambda x:get_x4(x,0.8))
    df['rsi_75'] = df['return'].rolling(3).apply(lambda x:get_x4(x,0.75))
    df['rsi_70'] = df['return'].rolling(3).apply(lambda x:get_x4(x,0.7))

    df['rsi_30'] = df['return'].rolling(3).apply(lambda x:get_x4(x,0.3))
    df['rsi_25'] = df['return'].rolling(3).apply(lambda x:get_x4(x,0.25))
    df['rsi_20'] = df['return'].rolling(3).apply(lambda x:get_x4(x,0.2))
    df['rsi_15'] = df['return'].rolling(3).apply(lambda x:get_x4(x,0.15))
    df['rsi_10'] = df['return'].rolling(3).apply(lambda x:get_x4(x,0.1))
    df['rsi_05'] = df['return'].rolling(3).apply(lambda x:get_x4(x,0.05))

    df_up = (1+df[['rsi_95','rsi_90','rsi_85','rsi_80','rsi_75','rsi_70']]).mul(df['close'],axis=0)
    df_down = (1+df[['rsi_30','rsi_25','rsi_20','rsi_15','rsi_10','rsi_05']]).mul(df['close'],axis=0)

    df_up = df_up.gt(df['close']*1.0002,axis=0).mul(df_up,axis=0).replace(0,np.nan)
    df_down = df_down.lt(df['close']*0.9998,axis=0).mul(df_down,axis=0).replace(0,np.nan)

    up_prices = df_up.loc[df_up.index[-2]]
    down_prices = df_down.loc[df_down.index[-2]]

    up_prices = sorted([round(x,价格小数位数) for x in list(up_prices) if not np.isnan(x)])
    down_prices = sorted([round(x,价格小数位数) for x in list(down_prices) if not np.isnan(x)], reverse=True)
    return up_prices,down_prices,df


def send(subject='测试', content='demo'):
    # url = 'https://open.larksuite.com/open-apis/bot/v2/hook/9b00dbf4-6271-4576-99b0-91b7739e05d5'
    url = "https://open.larksuite.com/open-apis/bot/v2/hook/264010a8-bc0b-4733-a37a-6e35087111d4"
    data = {
        "msg_type": "text",
        'content': {
            'text': subject + ' \n ' + content
        },
    }
    res = requests.post(url=url, data=json.dumps(data))


def send_info(url='https://open.larksuite.com/open-apis/bot/v2/hook/264010a8-bc0b-4733-a37a-6e35087111d4', subject='测试',
              content='demo'):
    data = {
        "msg_type": "text",
        'content': {
            'text': subject + ' \n ' + content
        },
    }
    res = requests.post(url=url, data=json.dumps(data))